
package fileby.util.plugins;

import fileby.util.plugins.Plugin;
import fileby.plugins.IPluggable;
import fileby.plugins.IPluginAnnotation;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 *
 * @author Ludwig Kjellstrom
 */
public class PluginLoader extends ClassLoader {

    public Plugin getPlugin(File f) throws InvalidPluginException {
        String name = null;
        String description = null;
        IPluggable pluggable = null;

        Class clazz;
        try {
            clazz = defineClass(f);
        } catch (FileNotFoundException ex) {
            throw new InvalidPluginException(ex.getMessage());
        } catch (IOException ex) {
            throw new InvalidPluginException(ex.getMessage());
        }

        if (hasIPluginAnnotation(clazz)) {
            name = ((IPluginAnnotation) clazz.getAnnotation(IPluginAnnotation.class)).name();
            description = ((IPluginAnnotation) clazz.getAnnotation(IPluginAnnotation.class)).description();
        }


        try {
            pluggable = (IPluggable) clazz.newInstance();
        } catch (InstantiationException ex) {
            throw new InvalidPluginException(ex.getMessage());
        } catch (IllegalAccessException ex) {
            throw new InvalidPluginException(ex.getMessage());
        }

        return new Plugin(name, description, pluggable);
    }

    private Class<?> defineClass(File f) throws FileNotFoundException, IOException {
        ByteArrayOutputStream classBuffer = new ByteArrayOutputStream();
        FileInputStream fileStream = new FileInputStream(f);

        int i = fileStream.read();
        while (i != -1) {
            classBuffer.write(i);
            i = fileStream.read();
        }

        byte[] data = classBuffer.toByteArray();
        classBuffer.close();
        fileStream.close();

        return defineClass(
                null,
                data,
                0,
                data.length);
    }

    private boolean hasIPluginAnnotation(Class clazz) {
        return clazz.getAnnotation(IPluginAnnotation.class) != null;
    }

}
